<template>

  <div>

    <!-- 属性定义列表 -->
    <el-table max-height="450" :data="properties">

      <el-table-column label="属性标识" align="center" prop="id"/>

      <el-table-column label="属性名称" align="center" prop="name"/>

      <el-table-column
        label="数据类型"
        align="center"
        prop="valueType.type"
        :filters="utils.getTableFiltersData(dict.type.iot_data_type)"
        :filter-method="utils.filterValueType"
      />

      <el-table-column
        label="属性值来源"
        align="center" prop="source"
        :filters="utils.getTableFiltersData(dict.type.iot_properties_value_source)"
        :filter-method="filterSource"
      >
        <template slot-scope="scope">
          <dict-tag :options="dict.type.iot_properties_value_source" :value="scope.row.expands.source"/>
        </template>
      </el-table-column>

      <el-table-column label="是否只读" align="center" prop="readOnly">
        <template slot-scope="scope">
          <dict-tag :options="dict.type.iot_read_only" :value="scope.row.expands.readOnly"/>
        </template>
      </el-table-column>

      <el-table-column label="属性值" align="center" prop="formatValue">
        <template slot-scope="scope">
          <el-link @click="viewOriginalData(scope.row)" type="primary">{{ scope.row.formatValue }}</el-link>
        </template>
      </el-table-column>

      <el-table-column label="消息时间" align="center" prop="timeString"/>

      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">

          <el-button
            size="mini"
            type="text"
            icon="el-icon-time"
            @click="viewHistoryRecord(scope.row)"
            v-hasPermi="['iot:device:list']"
          >历史
          </el-button>

          <el-button
            size="mini"
            type="text"
            icon="el-icon-bottom"
            @click="handleGetProperty(scope.row)"
            v-hasPermi="['iot:device:list']"
          >获取
          </el-button>

          <el-popover
            placement="bottom"
            width="200"
            trigger="click"
            @hide="handlePopoverHide"
          >
            <div style="text-align: right; margin: 0">
              <el-input placeholder="请输入内容" v-model="setValue" class="input-with-select">
                <el-button @click="handleSetProperty(scope.row)" slot="append" icon="el-icon-s-promotion"></el-button>
              </el-input>
            </div>
            <el-button
              v-show="!JSON.parse(scope.row.expands.readOnly)"
              class="button-spacing"
              size="mini"
              type="text"
              icon="el-icon-setting"
              v-hasPermi="['iot:device:debug']"
              slot="reference"
            >设置
            </el-button>
          </el-popover>

          <br/>
          <el-button
            class="button-spacing"
            size="mini"
            type="text"
            icon="el-icon-help"
            @click="handleProtocolStandby(scope.row)"
            v-hasPermi="['iot:device:edit']"
          >协议
          </el-button>

          <el-button
            size="mini"
            type="text"
            icon="el-icon-edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['iot:device:edit']"
          >编辑
          </el-button>

          <el-popconfirm
            title="确认删除？"
            @confirm="handleDelete(scope.row)"
          >
            <el-button
              class="button-spacing"
              size="mini"
              type="text"
              icon="el-icon-delete"
              v-hasPermi="['iot:device:remove']"
              slot="reference"
            >删除
            </el-button>
          </el-popconfirm>

        </template>
      </el-table-column>

    </el-table>

    <!-- 属性原始数据查看 -->
    <value-details ref="valueDetails"/>

    <!-- 属性历史数据查看 -->
    <properties-history ref="propertiesHistory"/>
  </div>

</template>

<script>

import { mapState } from 'vuex'
import PropertiesHistory from '@/views/iot/device/physical-model/propertiesHistory'
import ValueDetails from '@/views/iot/device/physical-model/valueDetails'
import utils from '@/utils/iot/metadata'
import {
  getDeviceLatestProperties,
  getDeviceRealtimeProperty,
  setDeviceProperties
} from '@/api/iot/device'
import { DataType } from '@/utils/iot/metadata/types/DataType'
import { formatDate } from '@/utils/dateUtils'

export default {
  name: 'PropertiesTable',
  components: {
    PropertiesHistory,
    ValueDetails
  },
  // 字典
  dicts: [
    // 数据类型
    'iot_data_type',
    // 属性值来源
    'iot_properties_value_source',
    // 是否只读
    'iot_read_only'
  ],
  data() {
    return {
      //属性列表
      properties: [],
      //引用
      utils,
      //设置参数
      setValue: undefined,
      // 最新属性值
      latestValues: new Map(),
      // 消息订阅id
      subIds: new Set()
    }
  },
  computed: {
    ...mapState({
      // 设备详情信息
      deviceDetailInfo: state => state.device.deviceDetailInfo,
      // 设备id
      deviceId: state => state.device.deviceId
    })
  },

  watch: {
    /** 监听设备详情信息变化，获取物模型属性数据*/
    deviceDetailInfo(data) {
      let metadata = JSON.parse(data.metadata)
      this.properties = metadata.properties
      this.setPropertiesValue()
    },

    /**
     * 监听属性物模型数据据变化
     * 当是物模型页面：
     * 1.则订阅属性实时数据
     * 2.获取最新属性数据
     * */
    'properties.length'() {
      // 获取全部最新设备属性
      this.getAllLatestProperties()
      // 事件数据订阅
      this.handleSubscribe()
    }
  },

  created() {
    let metadata = JSON.parse(this.deviceDetailInfo.metadata)
    this.properties = metadata.properties
    this.setPropertiesValue()
  },

  destroyed() {
    // 取消订阅
    this.handleUnsubscribe()
  },

  methods: {
    /** 属性来源筛选 */
    filterSource(value, row) {
      return row.expands.source === value
    },

    /** 查看历史记录 */
    viewHistoryRecord(row) {
      this.$refs.propertiesHistory.handleHistory(row.id)
    },

    /** 更新按钮操作 */
    handleUpdate(row) {
      this.$store.dispatch('EditDeviceProperties', row.id)
    },

    /** 删除按钮操作 */
    handleDelete(row) {
      // 删除属性
      this.$store.dispatch('DeleteDeviceMetadata', { type: 'properties', id: row.id })
      // 删除协议支持
      this.$store.dispatch('DeleteDeviceProtocolStandby', row.id)

    },

    /** 协议支持按钮操作 */
    handleProtocolStandby(row) {
      this.$store.dispatch('ViewDeviceProtocolStandby', { id: row.id, thingType: 'properties' })
    },

    /** 获取操作*/
    handleGetProperty(row) {

      const deviceId = this.deviceId
      const property = row.id

      let headers = {
        // 设备异步
        async: true,
        // sendAndForget: true
      }

      getDeviceRealtimeProperty(deviceId, property, headers)
        .then(({ data }) => {
          if (data === 'error.code.client_offline') {
            this.$modal.msgWarning('设备离线')
            return
          }
          if (data === 'error.code.request_handling') {
            this.$modal.msgSuccess('请求处理中')
            return
          }
          if (data === 'error.code.time_out') {
            this.$modal.msgSuccess('请求超时')
            return
          }

          if (JSON.stringify(data) === '{}') {
            this.$modal.msgSuccess('已发出')
            return
          }

          console.warn(data)

        })
        .catch(() => {
          this.$modal.msgError('请求失败')
        })
    },

    /** 设置操作*/
    handleSetProperty(row) {

      const deviceId = this.deviceId
      const property = row.id
      const value = this.setValue

      if (!value) {
        return
      }

      let params = {
        headers: {
          // 设备异步
          async: true,
          // sendAndForget: true
        },
        body: {}
      }

      params.body[property] = value

      setDeviceProperties(deviceId, params)
        .then(({ data }) => {
          if (data === 'error.code.client_offline') {
            this.$modal.msgWarning('设备离线')
            return
          }
          if (data === 'error.code.request_handling') {
            this.$modal.msgSuccess('请求处理中')
            return
          }
          if (data === 'error.code.time_out') {
            this.$modal.msgSuccess('请求超时')
            return
          }

          if (JSON.stringify(data) === '{}') {
            this.$modal.msgSuccess('已发出')
            return
          }

          console.warn(data)

        })
        .catch(() => {
          this.$modal.msgError('请求失败')
        })
    },

    /** Popover 隐藏时触发 */
    handlePopoverHide() {
      this.setValue = undefined
    },

    /** 属性数据订阅*/
    handleSubscribe() {

      const data = this.properties

      const productId = this.deviceDetailInfo.productId
      const deviceId = this.deviceId
      let ids = []
      data.forEach(datum => ids.push(datum.id))

      if (ids.length <= 0) {
        return
      }

      let id = `instance-info-property-${productId}-${deviceId}`

      this.subIds.add(id)

      // 属性订阅
      this.socket.send({
        method: 'event',
        params: {
          subEvent: 'sub',
          content: {
            type: 'sub',
            id,
            topic: `/device/${productId}/${deviceId}/message/property/report`,
          }
        }
      }).then(async data => {
        const payload = data.payload
        const properties = payload.properties
        for (let propertyId in properties) {
          if (!properties.hasOwnProperty(propertyId)) {
            continue
          }
          const value = properties[propertyId]
          const timeString = formatDate(payload.timestamp)
          const timestamp = payload.timestamp
          let index = this.properties.findIndex(item => item.id === propertyId)
          if (index === -1) {
            continue
          }
          let itemData = this.properties[index]
          await DataType.format(itemData.valueType, value).then(formatValue => itemData.formatValue = formatValue)
          itemData.timeString = timeString
          itemData.timestamp = timestamp
          itemData.originalValue = payload
          this.latestValues.set(propertyId, itemData)
          this.$set(this.properties, index, itemData)
        }

      })

    },

    /** 取消订阅 */
    handleUnsubscribe() {
      this.subIds.forEach(id => {
        // 取消事件订阅
        this.socket.send({
          method: 'event',
          params: {
            subEvent: 'unsub',
            content: {
              type: 'unsub',
              id,
            }
          }
        })
      })
    },

    /** 获取全部最新设备属性 */
    getAllLatestProperties() {
      const deviceId = this.deviceId
      getDeviceLatestProperties(deviceId).then((data = {}) => {
        const list = data.data || []
        list.forEach(row => this.latestValues.set(row.property, row))
        // 设置属性值
        this.setPropertiesValue()
      })
    },

    /** 给属性设置值*/
    setPropertiesValue() {

      this.properties.forEach((data, index) => {

        const latestValue = this.latestValues.get(data.id)

        if (latestValue) {
          data.formatValue = latestValue.formatValue
          data.timeString = this.parseTime(latestValue.timestamp)
          data.originalValue = latestValue

          this.$set(this.properties, index, data)
        }

      })
    },

    /** 查看详情 */
    viewOriginalData(data) {
      if (!data) {
        return
      }
      this.$refs.valueDetails.openDetails(data.originalValue, `详细信息（${data.id}）`)
    }

  }
}
</script>

<style lang="scss" scoped>
// 按钮间距
.button-spacing {
  margin-left: 10px
}
</style>
